package com.gill.aop.aspect;

import com.gill.aop.introduction.ExtraService;
import com.gill.aop.introduction.ExtraServiceImpl;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
//@Order(2)//当存在多个切面时，使用该注解指定切面的执行顺序
@Component
public class Aspect1 {

	/**
	 * 筛选出目标方法
	 * 1、* ：所有返回值
	 * 2、com.gill.aop.service.. 当前包、及其所有子包
	 * 3、* 所有类
	 * 4、* 所有方法
	 * 5、(..) 任意数量的参数
	 */
	@Pointcut(value = "execution(* com.gill.aop.service..*.*(..))")
	public void embed(){}

	/**
	 * 指定以下通知在目标方法的执行时间
	 */

	@Before(value = "embed()")
	public void before(JoinPoint joinPoint){
		System.out.println(joinPoint+"【切面1：Before通知：开始调用】");
	}

	@After(value = "embed()")
	public void after(JoinPoint joinPoint){
		System.out.println(joinPoint+"【切面1：After通知：结束调用】");
	}

	@Around(value = "embed()")
	public Object around(JoinPoint joinPoint) throws Throwable {
		// 注意：Around通知分为三部分逻辑，上半逻辑、执行方法、下半逻辑，执行的时间不同
		System.out.println("【切面1：Around通知的上半逻辑：在Before通知之前】");
		Object result;
		long start = System.currentTimeMillis();
		// 执行目标方法
		result = ((ProceedingJoinPoint)joinPoint).proceed();
		long end = System.currentTimeMillis();
		long pay_time = end - start;
		System.out.println(joinPoint+"【切面1：Around通知的下半逻辑：在After通知之前】");
		return result;
	}

	@AfterReturning(value = "embed()",returning = "result")
	public void afterReturning(JoinPoint joinPoint,Object result){
		System.out.println(joinPoint+"【切面1：AfterReturning通知】"+result);
	}

	@AfterThrowing(value = "embed()",throwing = "exception")
	public void afterThrowing(JoinPoint joinPoint,Exception exception){
		System.out.println(joinPoint+"【切面1：AfterThrowing通知】"+exception.getMessage());
	}

	// 测试一种不常用的Introduction通知（用来为某个类添加额外的功能，但该类不用实现该接口）
	@DeclareParents(value = "com.gill.aop..*",defaultImpl = ExtraServiceImpl.class)
	public ExtraService extraService;

}
